package KeyBoardMap;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Properties;

public class KeyBoard20 {
	private final int row0Panelty = 49;
	private final int lShiftPenalty = 28;
	private final int rShiftPenalty = 47;
	private Hashtable<Integer, Integer> keyCodeMap = null;
	private Hashtable<Character, Integer> charKeyMap = null;
	HashMap<Character, Double> pMap = null;

	private KeyBoard20() {
	}

	public KeyBoard20(String keyCodeFileName) {
		try {
			initKeyCodeMap(keyCodeFileName);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}// ctor

	public KeyBoard20(String keyCodeFileName, String charMapFileName) {
		try {
			initKeyCodeMap(keyCodeFileName);
			initCharMap(charMapFileName);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}// ctor

	public void initCharMap(String charMapFileName) throws IOException {
		charKeyMap = new Hashtable<Character, Integer>();
		Properties p = new Properties();
		p.clear();
		File f = new File(charMapFileName);
		FileInputStream fis = new FileInputStream(f);
		p.load(fis);
		System.out.println(p.keySet() + "" + p.keySet().size());
		System.out.println(p.values() + "" + p.values().size());
		for (Object o : p.keySet()) {
			charKeyMap.put(((String) o).charAt(0), Integer.parseInt(((String) p.get(o)).trim()));
		}
		fis.close();
	}

	private void initKeyCodeMap(String fileName) throws IOException {
		keyCodeMap = new Hashtable<Integer, Integer>();
		pMap = new HashMap<Character, Double>(94);
		Properties p = new Properties();
		p.clear();
		File f = new File(fileName);
		FileInputStream fis = new FileInputStream(f);
		p.load(fis);
		System.out.println(p.keySet() + "" + p.keySet().size());
		for (Object o : p.keySet()) {
			int length = Integer.parseInt(((String) p.get(o)).trim());
			keyCodeMap.put(Integer.parseInt((String) o), length);
		}
		fis.close();

	}

	public int calculate(String text) throws IOException {
		generateProbabilty(text);
		int ans = 0;
		int distance = 0;
		System.out.println(text.charAt(0));
		distance = getCharDistance(text.charAt(0)) * 2;
		ans += Math.max(distance, 0);
		System.out.print(text.charAt(0) + "" + ans + "+");
		ans += addPanelty(text.charAt(0));
		char prev = text.charAt(0);
		System.out.println();
		for (int i = 1; i < text.length(); i++) {
			char current = text.charAt(i);
			System.out.println(current);
			ans += do_calc(prev, current);
			prev = current;
			System.out.println();
		}
		if (text.length() == 1)
			ans += addPanelty(text.charAt(0));
		else
			ans += addPanelty(text.charAt(text.length() - 1));
		return ans;
	}

	public void generateProbabilty(String text) {
	//	HashMap<Character, Double> pMap = new HashMap<Character, Double>(94);
		int counter =0;
		for (int i = 0; i < text.length(); i++) {
			char c = text.charAt(i);
			if (c != ' ' || c != '\n' || c != '\t'){
				if (pMap.get(c) != null)
					pMap.put(c, pMap.get(c) + 1);
				else
					pMap.put(c, 0.0);
				counter++;
			}
		}
		for (Character c : pMap.keySet()) {
			pMap.put(c, pMap.get(c) / counter);
		}
		
	}

	private int addPanelty(char c) {
		int ans = 0;
		// numeric penalty
		if (charKeyMap.get(c) < 100) {
			System.out.print("Row0");
			ans += this.row0Panelty;
		}
		// shift penalty
		if (c >= 'A' && c <= 'Z') {
			System.out.print("SHIFT");
			if (isLeftDomain(c))
				ans += lShiftPenalty;
			else
				ans += rShiftPenalty;
		}
		System.out.print("Penalty:" + ans + "+");
		return ans;
	}

	private int do_calc(char prev, char current) {
		System.out.println(prev + "->" + current);
		int ans = 0;
		if (prev != current) {
			if ((isRow0(prev) && !isRow0(current)) || (!isRow0(prev) && isRow0(current))) {
				System.out.print(current + "" + this.row0Panelty + "+");
				ans += row0Panelty;
			}
			// Aa
			if ((Character.isUpperCase(prev) && !Character.isUpperCase(current)))
				ans += addPanelty(prev);
			if (!Character.isUpperCase(prev) && Character.isUpperCase(current)) {
				ans += addPanelty(current);
			}
			// upperCase from left domeain to right domain
			if (Character.isUpperCase(prev) && Character.isUpperCase(current)) {
				// if switched from domains:
				if ((isLeftDomain(prev) && !isLeftDomain(current)) || (!isLeftDomain(prev) && isLeftDomain(current))) {
					System.out.println("(LEFTSHIFT)" + this.lShiftPenalty + "+(RIGHTSHIFT)" + this.rShiftPenalty + "+");
					ans += this.lShiftPenalty;
					ans += this.rShiftPenalty;
				}
			}
			int distance = getCharDistance(current);
			if (distance > 0) {
				System.out.print(current + "" + getCharDistance(current) + "(*2)+");
				ans += getCharDistance(current) * 2;
			} else if (distance < 0)
				System.out.println("the char " + current + " is not recognized " + distance);
		}
		return ans;
	}

	private boolean isLeftDomain(char c) {
		return charKeyMap.get(c) % 100 < 6 || charKeyMap.get(c) == 113;
	}

	private boolean isRow0(char c) {
		return charKeyMap.get(c) < 100;
	}

	/* temp..... */
	public int getKeyDistance(int keyCode) {
		return keyCodeMap.get(keyCode);
	}

	/**
	 * return the distance for char c according to the KeyCode assignd to is
	 * 
	 * @param c
	 *            - char to search
	 * @return the distance in mm, -1 on error (char not found or CharKeyMap
	 *         wasn't initialized
	 */
	public int getCharDistance(char c) {
		if (charKeyMap.get(c) == null)
			return -1;
		Integer result = (charKeyMap == null ? -1 : charKeyMap.get(c));
		int distance = keyCodeMap.get(result);
		distance = (result == -1 ? -1 : distance);
		return distance;
	}

	/* temp! */

}
